﻿using System;
using System.Data.SqlClient;
using System.Globalization;
using System.Text;
using System.Xml;
using dmoz.Data;
using dmoz.Data.Bases;
using dmoz.Entities;
using Dmoz.Importer.Properties;

namespace Dmoz.Importer
{
    internal enum TypeOfLog
    {
        Full,
        Lite,
        None
    }

    /// <summary>
    /// Provides a way to bulk insert and process the DMOZ data to the database
    /// </summary>
    public sealed class DBHelper
    {
        private const string _importTextfilename = "Import.txt";
        private static int _categoryCount;
        private static string _catid;
        private static XmlTextWriter _importWriter;

        private static int _numberOfLog;
        private static int _resourceCount;
        private static int _rowCount;
        private static TypeOfLog _typeOfLog;

        /// <summary>
        /// Gets or sets the catid.
        /// </summary>
        /// <value>The catid.</value>
        public static string Catid
        {
            get { return _catid; }
            set { _catid = value; }
        }

        private DBHelper()
        {}

        /// <summary>
        /// Processes the specified path to RDF.
        /// </summary>
        /// <param name="pathToRDF">The path to RDF.</param>
        public static void Process(Uri pathToRDF)
        {
            _typeOfLog = TypeOfLog.Lite;
            _numberOfLog = 0;
            _rowCount = 0;

            _catid = null;

            DmozRdfHelper _dmozRdfHelper = new DmozRdfHelper(pathToRDF);

            _dmozRdfHelper.TopicLoaded += Parser_TopicLoaded;
            _dmozRdfHelper.NarrowLoaded += Parser_NarrowLoaded;
            _dmozRdfHelper.SymbolicLoaded += Parser_SymbolicLoaded;
            _dmozRdfHelper.RelatedLoaded += Parser_RelatedLoaded;
            _dmozRdfHelper.AltlangLoaded += Parser_AltlangLoaded;
            _dmozRdfHelper.EditorLoaded += Parser_EditorLoaded;
            _dmozRdfHelper.NewsgroupLoaded += Parser_NewsgroupLoaded;
            _dmozRdfHelper.TopicLeft += _dmozRdfHelper_TopicLeft;

            String FullOutputPath = Settings.Default.OutputPath;
            FullOutputPath = FullOutputPath.EndsWith("\\") ? FullOutputPath : FullOutputPath + "\\";
            FullOutputPath = String.Concat(FullOutputPath + _importTextfilename);

            _resourceCount = 0;

            // Now creating the import XML file
            _importWriter = new XmlTextWriter(FullOutputPath, Encoding.UTF8);
            _importWriter.WriteStartDocument(true);
            _importWriter.WriteStartElement("ROOT");
            _dmozRdfHelper.Parse();
            _importWriter.WriteEndDocument();
            _importWriter.Close();

            _typeOfLog = TypeOfLog.Full;
            _rowCount = 0;

            XmlImportDataReader _ImportReader = new XmlImportDataReader(FullOutputPath);

            using (
                SqlBulkCopy bulkCopy =
                    new SqlBulkCopy(DataRepository.ConnectionStrings["netTiersConnectionString"].ConnectionString,
                                    SqlBulkCopyOptions.KeepNulls & SqlBulkCopyOptions.KeepIdentity &
                                    SqlBulkCopyOptions.TableLock))
            {
                bulkCopy.DestinationTableName =
                    "dbo.Import";
                bulkCopy.BulkCopyTimeout = 300;
                bulkCopy.NotifyAfter = Settings.Default.BatchRowsNumber;
                bulkCopy.BatchSize = Settings.Default.BatchRowsNumber;
                bulkCopy.SqlRowsCopied += bulkCopy_SqlRowsCopied;

                DataRepository.ImportProvider.DataRequesting += ImportProvider_DataRequesting;

                try
                {
                    //Truncate the main DMOZ database tables
                    Log("Truncating DMOZ tables ...");
                    DataRepository.ImportProvider.TruncateMainTables();
                    Log("Tables truncated. Ready to import!");

                    // Bulk import data to the Import table
                    Log("Bulk importing the data ...");
                    bulkCopy.WriteToServer(_ImportReader);
                    Log("Bulk import complete.");

                    //Process the import data to the DMOZ tables
                    Log("Post-process the data on database side ...");
                    DataRepository.ImportProvider.PostProcess();
                    Log("All is done now! Enjoy!");
                }
                finally
                {
                    _ImportReader.Close();
                }
            }


            Log("END");
        }

        private static void ImportProvider_DataRequesting(object sender, CommandEventArgs e)
        {
            e.Command.CommandTimeout = DataRepository.Provider.DefaultCommandTimeout;
        }

        private static void bulkCopy_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
        {
            _rowCount += Settings.Default.BatchRowsNumber;
            _numberOfLog = 499;
            Log(String.Format(CultureInfo.InvariantCulture, "Import file rows : {0} items", _rowCount));
        }


        private static void ProcessResource(NodeLoadedEventArgs args, ResourceTypeList resourceType)
        {
            args.Catid = _catid;
            args.WriteXml(resourceType, _importWriter, ++_rowCount);

            _resourceCount++;
        }


        private static void _dmozRdfHelper_TopicLeft(object sender, NodeLoadedEventArgs args)
        {
            Log(String.Format(CultureInfo.InvariantCulture, "TOPIC LEFT : {0}", _catid));
            _catid = null;
        }

        private static void Parser_NewsgroupLoaded(object sender, NodeLoadedEventArgs args)
        {
            Log(String.Format(CultureInfo.InvariantCulture, "NEWSGROUP : {0}", args.Value));

            ProcessResource(args, ResourceTypeList.newsgroup);
        }


        private static void Parser_EditorLoaded(object sender, NodeLoadedEventArgs args)
        {
            Log(String.Format(CultureInfo.InvariantCulture, "EDITOR : {0}", args.Value));

            ProcessResource(args, ResourceTypeList.editor);
        }

        private static void Parser_AltlangLoaded(object sender, NodeLoadedEventArgs args)
        {
            Log(String.Format(CultureInfo.InvariantCulture, "ALTLANG : {0} {1}", args.Language, args.Value));

            ProcessResource(args, ResourceTypeList.altlang);
        }

        private static void Parser_RelatedLoaded(object sender, NodeLoadedEventArgs args)
        {
            Log(String.Format(CultureInfo.InvariantCulture, "RELATED : {0}", args.Value));

            ProcessResource(args, ResourceTypeList.related);
        }

        private static void Parser_SymbolicLoaded(object sender, NodeLoadedEventArgs args)
        {
            Log(String.Format(CultureInfo.InvariantCulture, "SYMBOLIC : {0} {1}", args.Value, args.Title));

            ProcessResource(args, ResourceTypeList.symbolic);
        }

        private static void Parser_NarrowLoaded(object sender, NodeLoadedEventArgs args)
        {
            Log(String.Format(CultureInfo.InvariantCulture, "NARROW : {0}", args.Value));

            ProcessResource(args, ResourceTypeList.narrow);
        }

        private static void Parser_TopicLoaded(object sender, NodeLoadedEventArgs args)
        {
            Log(String.Format(CultureInfo.InvariantCulture, "TOPIC : {0} {1} {2}", args.Value, args.Catid, args.Title));
            args.WriteXml(ResourceTypeList.topic, _importWriter, ++_rowCount);

            _categoryCount++;
            _catid = args.Catid;
        }

        private static void Log(string msg)
        {
            switch (_typeOfLog)
            {
                case TypeOfLog.Full:
                    Console.WriteLine(String.Format(CultureInfo.InvariantCulture, "{0} : {1}", DateTime.Now, msg));
                    break;
                case TypeOfLog.Lite:
                    _numberOfLog++;
                    if (_numberOfLog%500 == 0)
                    {
                        Console.WriteLine(String.Format(CultureInfo.InvariantCulture, "-- {0} -----------------------------", DateTime.Now));
                        Console.WriteLine(String.Format(CultureInfo.InvariantCulture, "Import file rows : {0} items", _rowCount));
                        Console.WriteLine(String.Format(CultureInfo.InvariantCulture, "Category : {0} items", _categoryCount));
                        Console.WriteLine(String.Format(CultureInfo.InvariantCulture, "Resource : {0} items", _resourceCount));
                    }
                    break;
            }
        }
    }
}